package com.gmrz.uap.cfg;

import com.gmrz.uap.dict.DictConst;
import com.gmrz.uap.dict.DictService;
import com.gmrz.uap.model.Dict;
import com.jfinal.core.JFinal;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.dialect.*;
import com.jfinal.plugin.ehcache.CacheKit;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;
import java.net.MalformedURLException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

public class SystemConst {
    private static final Logger LOG = LogManager.getLogger(SystemConst.class);

    public static final String SYSTEM_CONFIG_FILE = "application.properties";
    public static final String CONFIG_DEV_MODE = "devMode";

    /**
     * 超级管理员角色
     */
    public static final String SUPER_ROLE_ID = "923a151cce714758b26acc31cd9ec212";
    /**
     * 省级管理员角色
     */
    public static final String PROVINCE_ROLE_ID = "c41a836ef7bd4604a310a0414a223395";
    /**
     * 机构管理员角色
     */
    public static final String ORGANIZATION_ROLE_ID = "3559623459bb4b6eba2190396ad9ce29";


    /*===================== 数据库类型 ======================*/
    public static final String DB_TYPE_ORACLE = "oracle";
    public static final String DB_TYPE_MYSQL = "mysql";
    public static final String DB_TYPE_SQLSERVER = "sqlserver";
    public static final String DB_TYPE_POSTGRES = "postgres";
    public static final String DB_TYPE_DB2 = "db2";
    public static final String DB_TYPE_SQLITE = "sqlite";

    public static final String DB_TEST_CONNECTION = "select 1";

    public static final String SESSION_USER = "UserInfo";
    public static final String COOKIE_TENANT_ID = "tenantId";
    public static final String DEFAULT_TENANT_ID = "default";
    public static final String LOGIN_PATH = "/user/login";

    public static final String _DEFAULT_SEPARATOR_COMMA = ",";
    public static final String _DEFAULT_SEPARATOR_DOT = ".";
    public static final int MAX_RESOURCE_URL_LENGTH = 25;

    public static final String DEFAULT_DATE_FOMATTER = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_FOMATTER_YEARMONTH = "yyyy-MM";
    public static final String DEFAULT_DATE_FOMATTER_YEARMONTHDAY = "yyyy-MM-dd";

    public static final String COOKIE_I18N = "_locale";

    public static final String TENANTS = "tenants";
    public static final String DEFAULT_THEME = "current-skin";

    public static final String VIEW_EXTENDSION = ".html";


    public static final String MESSAGE_RESULT_FLAG = "flag";
    public static final String MESSAGE_RESULT_MSG = "message";


    public static final String AUTHMETADATA_AAID = "aaid";
    public static final String AUTHMETADATA_DESCRIPTION = "description";
    public static final String AUTHMETADATA_AUTHENTICATORVERSION = "authenticatorVersion";


    public static final String DB_JNDI_NAME = "jdbc/fidods";
    public static final String DB_JNDI_FIDOLOG = "jdbc/fidologds";
        public static final String DB_FIDOLOG_DATASOURCE = "fidolog_datasource";
    //public static final String SYSTEM_DEFAULT_LOCALE = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();

    public static final String SYSTEM_DEFAULT_LOCALE = "zh_CN";

    public static final String DATATABLE_PAGINATE_OFFSET = "page";
    public static final Integer DATATABLE_PAGINATE_OFFSET_DEFAULT = 1;
    public static final String DATATABLE_PAGINATE_LIMIT = "rows";
    public static final Integer DATATABLE_PAGINATE_LIMIT_DEFAULT = 10;
    public static final String DATATABLE_PAGINATE_SORT = "sort";
    public static final String DATATABLE_PAGINATE_ORDER = "order";
    public static final String DATATABLE_PAGINATE_ORDER_DEFAULT = "desc";
    public static final String DATATABLE_PAGINATE_TOTAL = "total";
    public static final String DATATABLE_PAGINATE_ROWS = "rows";
    public static final String DATATABLE_MAX_PAGE_COUNT_KEY = "max_page_count";
    public static final int DATATABLE_MAX_PAGE_COUNT = 30000;

    public static final String DEFAULT_ORDERBY_CREATETS = "createts";
    public static final String DEFAULT_ORDERBY_ORDERNUMBER = "order_number";


    public static final String POLICY_NAME = "POLICY";


    public static final String PROTOCOL_UAF = "uaf";
    public static final String PROTOCOL_FIDO2 = "fido2";
    public static final String PROTOCOL_FIDO2_AAGUID = "aaguid";
    public static final int AAID_LENGTH = 9;

    // 获取项目启动时所连接数据库的类型
    public static  String DB_TYPE ;


    /*============================= 元数据-证书安全级别 ===================================*/
    public static final String AUTH_METADATA_NODE_SECURELEVEL = "secureLevel";
    public static final int AUTH_METADATA_NODE_SECURELEVEL_1 = 1;
    public static final int AUTH_METADATA_NODE_SECURELEVEL_2 = 2;


    /*============================= 证书安全级别 ===================================*/

    // TEE ：3
    public static final String CERT_SECURE_LEVEL_TEE = "TEE";
    // TEE+TUI ：2
    public static final String CERT_SECURE_LEVEL_TEEANDTUI = "TEE+TUI";
    // SE ：1
    public static final String CERT_SECURE_LEVEL_SE = "SE";





    /**
     * 根据验证类型获数值取对应的实际内容
     *
     * @param authType
     * @return 国际化KEY
     */
    public static String getAuthType(String authType) {
        String authTypeContent = null;

        List<Dict> authTypeList = DictService.me.getDictListByDictTypeID(DictConst.DICT_TYPE_STATICS_AUTH_AUTH_TYPE_ID);
        for (Dict dict : authTypeList) {
            if (StringUtils.equalsIgnoreCase(dict.getDictText(), authType)) {
                authTypeContent = dict.getDictName();
                break;
            }
        }
        return authTypeContent;
    }

    /**
     * 根据交易类型获数值取对应的实际内容
     *
     * @param transType
     * @return 国际化KEY
     */
    public static String getTransType(String transType) {
        String transTypeContent = null;

        List<Dict> transTypeList = DictService.me.getDictListByDictTypeID(DictConst.DICT_TYPE_TRANS_TYPE_ID);
        for (Dict dict : transTypeList) {
            if (StringUtils.equalsIgnoreCase(dict.getDictText(), transType)) {
                transTypeContent = dict.getDictName();
                break;
            }
        }

        return transTypeContent;
    }

    //认证类型MAP类型
    public static final String AUTHTYPE_ID = "id";
    public static final String AUTHTYPE_AUTHNUM = "authNum";
    public static final String AUTHTYPE_AUTHKEY = "authKey";


    public static final String RESPONSE_RESULT_FLAG = "flag";
    public static final String RESPONSE_RESULT_MESSAGE = "message";
    public static final String RESPONSE_RESULT_DATA = "data";
    public static final String RESPONSE_RESOURCE_MESSAGE = "message2";

    public static final String MAX_NUM_POLICY_AAID = "uaf.policy.max.match.criterias.allowed";


    /**
     * 获取是否是开发模式还是生产模式
     *
     * @return boolean
     */
    public static boolean getDevMode() {
        return PropKit.use(SYSTEM_CONFIG_FILE).getBoolean("devMode", false);
    }


    public static Dialect getDialectByDatabaseProductName(DataSource dataSource) {
        Dialect dialect = null;
        String databaseProductName = null;

        try {
            databaseProductName = dataSource.getConnection().getMetaData().getDatabaseProductName().toLowerCase();
        } catch (SQLException e) {
            LOG.error("根据数据库名称获取数据库类型出现异常", e);
        }

        //根据不同的数据库设置对应的数据库方言
        if (databaseProductName.contains(DB_TYPE_MYSQL)) {
            dialect = new MysqlDialect();
        } else if (databaseProductName.contains(DB_TYPE_ORACLE)) {
            dialect = new OracleDialect();
        } else if (databaseProductName.contains(DB_TYPE_SQLSERVER)) {
            dialect = new SqlServerDialect();
        } else if (DB_TYPE_POSTGRES.equalsIgnoreCase(databaseProductName)) {
            dialect = new PostgreSqlDialect();
        } else if (databaseProductName.contains(DB_TYPE_SQLITE)) {
            dialect = new Sqlite3Dialect();
        } else {
            dialect = new AnsiSqlDialect();
        }

        return dialect;
    }


    public static String getDbTypeByDatabase(DataSource dataSource, String fidoDB_or_fidoLogDB) {
        String databaseProductName = "";
        String dbTye = "";

        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            databaseProductName = conn.getMetaData().getDatabaseProductName().toLowerCase();
        } catch (SQLException e) {
            LOG.error("根据数据源获取数据库类型出现异常", e);

        }finally {
            if (null != conn){
                try {
                    conn.close();
                } catch (SQLException e) {
                    LOG.error("无法关闭 "+ fidoDB_or_fidoLogDB +" 数据库连接 ", e);
                }
            }
        }

        if (databaseProductName.contains(DB_TYPE_MYSQL)) {
            dbTye = DB_TYPE_MYSQL;
        } else if (databaseProductName.contains(DB_TYPE_ORACLE)) {
            dbTye = DB_TYPE_ORACLE;
        } else if (databaseProductName.contains(DB_TYPE_DB2)) {
            dbTye = DB_TYPE_DB2;
        } else if (databaseProductName.contains(DB_TYPE_SQLSERVER)) {
            dbTye = DB_TYPE_SQLSERVER;
        } else if (databaseProductName.contains(DB_TYPE_POSTGRES)) {
            dbTye = DB_TYPE_POSTGRES;
        } else if (databaseProductName.contains(DB_TYPE_SQLITE)) {
            dbTye = DB_TYPE_SQLITE;
        }

        LOG.info("当前数据库类型为=" + dbTye);

        return dbTye;
    }


    public static Dialect getDialectByDatabaseProductName(String databaseProductName) {
        Dialect dialect = null;

        //根据不同的数据库设置对应的数据库方言
        if (DB_TYPE_MYSQL.equalsIgnoreCase(databaseProductName)) {
            dialect = new MysqlDialect();
        } else if (DB_TYPE_ORACLE.equalsIgnoreCase(databaseProductName)) {
            dialect = new OracleDialect();
        } else if (DB_TYPE_SQLSERVER.equalsIgnoreCase(databaseProductName)) {
            dialect = new SqlServerDialect();
        } else if (DB_TYPE_POSTGRES.equalsIgnoreCase(databaseProductName)) {
            dialect = new PostgreSqlDialect();
        } else if (DB_TYPE_SQLITE.equalsIgnoreCase(databaseProductName)) {
            dialect = new Sqlite3Dialect();
        } else {
            dialect = new AnsiSqlDialect();
        }

        return dialect;
    }

    /**
     * 根据数据源获取数据库类型
     *
     * @param dataSource 数据源
     * @return String 数据库类型
     */
    public static String getProductDatabaseNameByDataSource(DataSource dataSource) {
        String productDatabasenName = null;

        try {

            productDatabasenName = dataSource.getConnection().getMetaData().getDatabaseProductName();

        } catch (SQLException e) {
            LOG.info("productDatabasenName=======" + productDatabasenName);
            LOG.error("根据数据源获取数据库类型出现异常", e);
        }

        return productDatabasenName;
    }

    /**
     * 根据JNDI获取数据库类型信息
     *
     * @param jndi JNDI名称
     * @return String 数据库类型
     */
    public static String getProductDatabaseNameByJNDI(String jndi) {
        String productDatabaseName = null;
        DataSource dataSource = null;

        try {
            dataSource = (DataSource) new InitialContext().lookup("java:comp/env/" + jndi);
            productDatabaseName = dataSource.getConnection().getMetaData().getDatabaseProductName();
        } catch (SQLException e) {
            LOG.error("获取数据源信息出现异常", e);
        } catch (NamingException e) {
            LOG.error("没有找到" + jndi + "相关的数据源信息", e);
        }
        return productDatabaseName;
    }

    /**
     * 根据前端发送过来的参数经过处理后得到JFinal需要的页号
     *
     * @param pageSize   行数
     * @param pageNumber 页码
     * @return int 处理后的页码
     */
    public static int processPageNumber(int pageSize, int pageNumber) {
        return (pageNumber / pageSize) + 1;
    }

    /**
     * 获取WEBROOT所在路径，兼容Tomcat和Weblogic
     *
     * @return 绝对路径
     */
    public static String getWebRootUrl() {
        String fileDirPath = JFinal.me().getServletContext().getRealPath("/");
        if (fileDirPath == null) {
            //如果返回为空，则表示服务器为weblogic，则需要使用另外的方法
            try {
                return JFinal.me().getServletContext().getResource("/").getFile();
            } catch (MalformedURLException e) {
                LOG.info("获取项目的根目录出错！", e);
            }
        } else {
            return fileDirPath;
        }
        LOG.info("WEBROOT目录 ==> " + fileDirPath);

        return fileDirPath;
    }

    /**
     * 获取WEBROOT所在路径，兼容Tomcat和Weblogic
     *
     * @param session
     * @return 绝对路径
     */
    public static String getWebRootUrl(HttpSession session) {
        String fileDirPath = session.getServletContext().getRealPath("/");
        if (fileDirPath == null) {
            //如果返回为空，则表示服务器为weblogic，则需要使用另外的方法
            try {
                return session.getServletContext().getResource("/").getFile();
            } catch (MalformedURLException e) {
                LOG.info("获取项目的根目录出错！", e);
            }
        } else {
            return fileDirPath;
        }

        LOG.info("WEBROOT目录 ==> " + fileDirPath);

        return fileDirPath;
    }


    public static final String CACHE_DICT = "UAP_DICT_CACHE";
    public static final String CACHE_DICT_TYPE_ID_SYSTEM_CONST = "56b4231b85ce4ed0b7bb942579bc2fba";
    public static final String CACHE_DICT_TYPE_ID_SYSTEM_CONST_KEY = "systemConstCache";

    public static final String CACHE_DICT_TYPE_SYSTEMNAME = "systemName";
    public static final String CACHE_DICT_TYPE_RETAINFIDOLOGDAYS = "retainFidoLogDays";
    public static final String CACHE_DICT_TYPE_ISDELETEFIDOLOGSWITCH = "isDeleteFidoLogSwitch";


    public static Map<String, Dict> getDictSystemConst() {
        Map<String, Dict> systemConstCache = CacheKit.get(CACHE_DICT, CACHE_DICT_TYPE_ID_SYSTEM_CONST_KEY);
        if (systemConstCache == null) {
            List<Dict> dictList = DictService.me.getDictListByDictTypeID(CACHE_DICT_TYPE_ID_SYSTEM_CONST);
            Map<String, Dict> systemConstCacheTmp = new HashMap<String, Dict>();
            for (Dict dict : dictList) {
                systemConstCacheTmp.put(dict.getDictName(), dict);
            }
            CacheKit.put(CACHE_DICT, CACHE_DICT_TYPE_ID_SYSTEM_CONST_KEY, systemConstCacheTmp);
            return systemConstCacheTmp;
        } else {
            return systemConstCache;
        }
    }


    public static int getTotalPage(int totalRow, int rows) {
        int totalPage = totalRow / rows;
        if (totalRow % rows != 0) {
            totalPage++;
        }
        return totalPage;
    }

}
